package org.su.generalmvc.core;

import org.su.generalmvc.IParamBinder;
import org.su.generalmvc.config.BindBeanException;
import org.su.generalmvc.config.XSSHConfig;
import org.su.generalmvc.entity.PojoCache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.web.context.WebApplicationContext;

import java.util.HashMap;
import java.util.Map;

/**
 * spring 容器包装类，封装bean注入、获取和删除
 * 
 * @author yangchuan
 * @since 2012-03-6
 * @version 1.0
 */
public class SpringApplicationContext implements IXsshApplicationContext {

	private ApplicationContext context = null;

	private DefaultListableBeanFactory dlbf = null;


	private XSSHConfig config = null;

	protected final Log logger = LogFactory.getLog(getClass());

	private static final String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;

	private Map<String, XsshPackage> packages = new HashMap<String, XsshPackage>();

	private Map<String, ActionProxy> actions = new HashMap<String, ActionProxy>();

	private Map<String, ActionProxy> getActions = new HashMap<String, ActionProxy>();
	private Map<String, ActionProxy> postActions = new HashMap<String, ActionProxy>();
	private Map<String, ActionProxy> allActions = new HashMap<String, ActionProxy>();


	private Map<String, PojoCache> pojoContext;

	private int serverId;

    private IServiceContext serviceContext;

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#getActions()
	 */
	@Override
	public Map<String, ActionProxy> getActions() {
		return actions;
	}
	
	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#setActions(java.util.Map)
	 */
	@Override
	public void setActions(Map<String, ActionProxy> actions) {
		this.actions = actions;
	}

	public Map<String, ActionProxy> getGetActions() {
		return getActions;
	}

	@Override
	public void setGetActions(Map<String, ActionProxy> getActions) {
		this.getActions = getActions;
	}

	public Map<String, ActionProxy> getPostActions() {
		return postActions;
	}

	@Override
	public void setPostActions(Map<String, ActionProxy> postActions) {
		this.postActions = postActions;
	}

	public Map<String, ActionProxy> getAllActions() {
		return allActions;
	}

	@Override
	public void setAllActions(Map<String, ActionProxy> allActions) {
		this.allActions = allActions;
	}

	/* (non-Javadoc)
         * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#getConfig()
         */
	@Override
	public XSSHConfig getConfig() {
		return config;
	}
	
	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#setConfig(com.xssh.generalmvc.web.config.XSSHConfig)
	 */
	@Override
	public void setConfig(XSSHConfig config) {
		this.config = config;
	}


	public SpringApplicationContext(){
		
	}
	
	
	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#isSpringContext()
	 */
	@Override
	public boolean isSpringContext() {
		return true;
	}

	private ApplicationContext prepareRootApplicationContext() {
		ApplicationContext applicationContext = (ApplicationContext) serviceContext
				.getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		return applicationContext;
	}

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#init(javax.servlet.ServletContext)
	 */
	@Override
	public void init(IServiceContext serviceContext) {
		this.serviceContext = serviceContext;
		context = prepareRootApplicationContext();
		dlbf = (DefaultListableBeanFactory) context
				.getAutowireCapableBeanFactory();
	}
	

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#addPackage(java.lang.String, com.xssh.generalmvc.web.core.XsshPackage)
	 */
	@Override
	public void addPackage(String packeageName, XsshPackage xsshPackage) {
		if (!packages.containsKey(packeageName)) {
			packages.put(packeageName, xsshPackage);
		}
	}

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#getPackage(java.lang.String)
	 */
	@Override
	public XsshPackage getPackage(String packeageName) {
		return packages.get(packeageName);
	}

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#addBean(java.lang.String, java.lang.Class)
	 */
	@Override
	public Object addBean(String beanName, Class<?> beanClass) {

		if (!context.containsBean(beanName)) {
			Object obj = dlbf.createBean(beanClass,
					AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
			dlbf.registerSingleton(beanName, obj);
			return obj;
		} else {
			throw new BindBeanException(beanName);
		}
	}

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#addBean(java.lang.String, java.lang.String)
	 */
	@Override
	public Object addBean(String beanName, String beanClass) {
		try {
			return addBean(beanName, Class.forName(beanClass));
		} catch (ClassNotFoundException e) {
			throw new BindBeanException(beanName, e);
		}
	}

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#getBean(java.lang.String)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public <T> T getBean(String beanName) {
		try {
			return (T) context.getBean(beanName);
		} catch (Exception e) {
			return null;
		}
		
	}

	@Override
	public boolean containsBean(String beanName) {
		return context.containsBean(beanName);
	}

    /**
     * 获取写一层上下文环境
     *
     * @return
     */
    @Override
    public IServiceContext getServiceContext() {
        return serviceContext;
    }


    /* (non-Javadoc)
     * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#removeBean(java.lang.String)
     */
	@Override
	public void removeBean(String beanName) {
		dlbf.removeBeanDefinition(beanName);
	}

	/* (non-Javadoc)
	 * @see com.xssh.generalmvc.web.core.IXsshApplicationContext#destroy()
	 */
	@Override
	public void destroy() {
		if (context != null) {
			try {
				if (context instanceof AbstractApplicationContext) {
					((AbstractApplicationContext) context).close();
				}
			} catch (Throwable e) {
				logger.error("", e);
			}
		}
	}

	/**
	 * 是否使用数据库
	 * @return
	 */
	public boolean isUseDB(){
		return config.isUseDB();
	}
	
	public Map<String, PojoCache> getPojoContext(){
		if(this.pojoContext == null){
			this.pojoContext = new HashMap<String, PojoCache>();
		}
		return this.pojoContext;
	}
	
	public int getServerId(){
		return serverId;
	}

	public void setServerId(int serverId) {
		this.serverId = serverId;
	}


    @Override
    public IParamBinder getParamBinder() {
        return getBean(config.getContextPrefix()+":"+IParamBinder.class.getName());
    }

}
